{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\ipykernel_launcher.py:14: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version\n",
      "of pandas will change to not sort by default.\n",
      "\n",
      "To accept the future behavior, pass 'sort=False'.\n",
      "\n",
      "To retain the current behavior and silence the warning, pass 'sort=True'.\n",
      "\n",
      "  \n"
     ]
    }
   ],
   "source": [
    "# LightGBMRegressor\n",
    "# 交叉验证 MAE: 473.3349762655072\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.model_selection import KFold\n",
    "from lightgbm.sklearn import LGBMRegressor\n",
    "from sklearn.metrics import mean_absolute_error\n",
    "\n",
    "# 首先使用 Pandas 库读入训练数据和测试数据，保存到 Train_data 和 Test_data 变量中。\n",
    "Train_data = pd.read_csv('../data/used_car_train_20200313.csv',sep=' ')  # handle_used_car_train.csv\n",
    "Test_data = pd.read_csv('../data/used_car_testA_20200313.csv', sep=' ')\n",
    "\n",
    "# 使用 pd.concat() 函数将训练数据和测试数据合并，并保存到 df 变量中。\n",
    "df = pd.concat([Train_data, Test_data], ignore_index=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对 'price' 做对数变换，使用 np.log1p() 函数。\n",
    "df['price'] = np.log1p(df['price'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用众数填充缺失值\n",
    "df['fuelType'] = df['fuelType'].fillna(0)\n",
    "df['gearbox'] = df['gearbox'].fillna(0)\n",
    "df['bodyType'] = df['bodyType'].fillna(0)\n",
    "df['model'] = df['model'].fillna(0)\n",
    "\n",
    "# 处理异常值，主要是将功率大于 600 的标为 600\n",
    "df['power'] = df['power'].map(lambda x: 600 if x > 600 else x)  # 赛题限定power<=600\n",
    "# 将 ‘notRepairedDamage’ 中的缺失值替换为 None\n",
    "df['notRepairedDamage'] = df['notRepairedDamage'].astype('str').apply(lambda x: x if x != '-' else None).astype(\n",
    "    'float32')\n",
    "\n",
    "# 对可分类的连续特征进行分桶，例如将功率（power）分为 31 组，车型（model）分为 24 组。\n",
    "bin = [i * 10 for i in range(31)]\n",
    "df['power_bin'] = pd.cut(df['power'], bin, labels=False)\n",
    "\n",
    "bin = [i * 10 for i in range(24)]\n",
    "df['model_bin'] = pd.cut(df['model'], bin, labels=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对日期数据进行处理，主要是提取年，月，日等信息和计算二手车使用时间。\n",
    "from datetime import datetime\n",
    "\n",
    "\n",
    "def date_process(x):\n",
    "    year = int(str(x)[:4])\n",
    "    month = int(str(x)[4:6])\n",
    "    day = int(str(x)[6:8])\n",
    "\n",
    "    if month < 1:\n",
    "        month = 1\n",
    "\n",
    "    date = datetime(year, month, day)\n",
    "    return date\n",
    "\n",
    "\n",
    "df['regDate'] = df['regDate'].apply(date_process)\n",
    "df['creatDate'] = df['creatDate'].apply(date_process)\n",
    "df['regDate_year'] = df['regDate'].dt.year\n",
    "df['regDate_month'] = df['regDate'].dt.month\n",
    "df['regDate_day'] = df['regDate'].dt.day\n",
    "df['creatDate_year'] = df['creatDate'].dt.year\n",
    "df['creatDate_month'] = df['creatDate'].dt.month\n",
    "df['creatDate_day'] = df['creatDate'].dt.day\n",
    "\n",
    "# 使用天数\n",
    "df['car_age_day'] = (df['creatDate'] - df['regDate']).dt.days\n",
    "# 使用年数\n",
    "df['car_age_year'] = round(df['car_age_day'] / 365, 1)\n",
    "\n",
    "# 对行驶路程和功率数据进行统计，例如：计算行驶路程与功率的最大值、最小值、中位数和均值等。\n",
    "kk = ['kilometer', 'power']\n",
    "t1 = Train_data.groupby(kk[0], as_index=False)[kk[1]].agg(\n",
    "    {kk[0] + '_' + kk[1] + '_count': 'count', kk[0] + '_' + kk[1] + '_max': 'max',\n",
    "     kk[0] + '_' + kk[1] + '_median': 'median',\n",
    "     kk[0] + '_' + kk[1] + '_min': 'min', kk[0] + '_' + kk[1] + '_sum': 'sum', kk[0] + '_' + kk[1] + '_std': 'std',\n",
    "     kk[0] + '_' + kk[1] + '_mean': 'mean'})\n",
    "df = pd.merge(df, t1, on=kk[0], how='left')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 为部分属性列的数据生成新的特征，主要是通过对 V0、V3、V8 和 V12 四个特征进行组合生成新的二元和三元特征。\n",
    "num_cols = [0, 3, 8, 12]\n",
    "for i in num_cols:\n",
    "    for j in num_cols:\n",
    "        df['new' + str(i) + '*' + str(j)] = df['v_' + str(i)] * df['v_' + str(j)]\n",
    "\n",
    "for i in num_cols:\n",
    "    for j in num_cols:\n",
    "        df['new' + str(i) + '+' + str(j)] = df['v_' + str(i)] + df['v_' + str(j)]\n",
    "\n",
    "for i in num_cols:\n",
    "    for j in num_cols:\n",
    "        df['new' + str(i) + '-' + str(j)] = df['v_' + str(i)] - df['v_' + str(j)]\n",
    "\n",
    "for i in range(15):\n",
    "    df['new' + str(i) + '*year'] = df['v_' + str(i)] * df['car_age_year']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在训练模型的过程中，使用了 LightGBMRegressor 作为模型，采用四个参数（'n_estimators'、'learning_rate'、'num_leaves' 和 'lambda_l2'）进行调参。\n",
    "其中：\n",
    "'n_estimators'：表示树的数量，设置得越多，模型越复杂，训练得越慢。根据经验，一般取 100 至 10000 之间的数。\n",
    "\n",
    "'learning_rate'：表示学习率，是一个重要的参数，取值越小，需要的树的数量越多，训练得越慢，但一般能得到更好的性能。\n",
    "\n",
    "'num_leaves'：表示基分类器的数量，取值越大，模型的复杂度越高，但可能会导致过拟合。\n",
    "\n",
    "'lambda_l2'：表示 L2 正则化系数，取值越大，正则化效果越强，可以防止过拟合。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在特征工程中，对数据进行了缺失值填充、数据统计和特征组合等操作。这些操作都是为了更好地利用数据中包含的信息，提高模型的性能。\n",
    "\n",
    "在使用 LightGBMRegressor 对数据进行训练时，还使用了 K-Fold 交叉验证（K=4），通过这种方式可以更准确地评估模型的性能，并防止模型过拟合。\n",
    "\n",
    "最终得到的结果通过将五次模型训练得到的结果平均作为最终预测结果，并将结果保存到文件中供提交。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--------------------- 第 1 折 ---------------------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:726: UserWarning: 'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. Pass 'early_stopping()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. \"\n",
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:736: UserWarning: 'verbose' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'verbose' argument is deprecated and will be removed in a future release of LightGBM. \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[LightGBM] [Warning] feature_fraction is set=0.8, colsample_bytree=1.0 will be ignored. Current value: feature_fraction=0.8\n",
      "[LightGBM] [Warning] bagging_fraction is set=0.8, subsample=1.0 will be ignored. Current value: bagging_fraction=0.8\n",
      "[LightGBM] [Warning] lambda_l2 is set=2, reg_lambda=0.0 will be ignored. Current value: lambda_l2=2\n",
      "[LightGBM] [Warning] bagging_freq is set=1, subsample_freq=0 will be ignored. Current value: bagging_freq=1\n",
      "[300]\tvalid_0's l1: 0.12678\n",
      "[600]\tvalid_0's l1: 0.12073\n",
      "[900]\tvalid_0's l1: 0.118024\n",
      "[1200]\tvalid_0's l1: 0.116348\n",
      "[1500]\tvalid_0's l1: 0.115338\n",
      "[1800]\tvalid_0's l1: 0.11457\n",
      "[2100]\tvalid_0's l1: 0.113987\n",
      "[2400]\tvalid_0's l1: 0.11348\n",
      "[2700]\tvalid_0's l1: 0.113196\n",
      "[3000]\tvalid_0's l1: 0.11287\n",
      "[3300]\tvalid_0's l1: 0.112683\n",
      "[3600]\tvalid_0's l1: 0.112477\n",
      "[3900]\tvalid_0's l1: 0.112322\n",
      "[4200]\tvalid_0's l1: 0.112172\n",
      "[4500]\tvalid_0's l1: 0.11207\n",
      "[4800]\tvalid_0's l1: 0.111967\n",
      "[5100]\tvalid_0's l1: 0.11186\n",
      "[5400]\tvalid_0's l1: 0.111823\n",
      "[5700]\tvalid_0's l1: 0.111728\n",
      "[6000]\tvalid_0's l1: 0.111626\n",
      "[6300]\tvalid_0's l1: 0.111537\n",
      "[6600]\tvalid_0's l1: 0.111477\n",
      "[6900]\tvalid_0's l1: 0.111425\n",
      "[7200]\tvalid_0's l1: 0.111365\n",
      "[7500]\tvalid_0's l1: 0.111322\n",
      "[7800]\tvalid_0's l1: 0.111286\n",
      "[8100]\tvalid_0's l1: 0.111254\n",
      "[8400]\tvalid_0's l1: 0.111235\n",
      "[8700]\tvalid_0's l1: 0.111217\n",
      "[9000]\tvalid_0's l1: 0.111183\n",
      "[9300]\tvalid_0's l1: 0.111154\n",
      "[9600]\tvalid_0's l1: 0.111115\n",
      "[9900]\tvalid_0's l1: 0.111116\n",
      "--------------------- 第 2 折 ---------------------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:726: UserWarning: 'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. Pass 'early_stopping()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. \"\n",
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:736: UserWarning: 'verbose' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'verbose' argument is deprecated and will be removed in a future release of LightGBM. \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[LightGBM] [Warning] feature_fraction is set=0.8, colsample_bytree=1.0 will be ignored. Current value: feature_fraction=0.8\n",
      "[LightGBM] [Warning] bagging_fraction is set=0.8, subsample=1.0 will be ignored. Current value: bagging_fraction=0.8\n",
      "[LightGBM] [Warning] lambda_l2 is set=2, reg_lambda=0.0 will be ignored. Current value: lambda_l2=2\n",
      "[LightGBM] [Warning] bagging_freq is set=1, subsample_freq=0 will be ignored. Current value: bagging_freq=1\n",
      "[300]\tvalid_0's l1: 0.126297\n",
      "[600]\tvalid_0's l1: 0.119785\n",
      "[900]\tvalid_0's l1: 0.117068\n",
      "[1200]\tvalid_0's l1: 0.115651\n",
      "[1500]\tvalid_0's l1: 0.114751\n",
      "[1800]\tvalid_0's l1: 0.11415\n",
      "[2100]\tvalid_0's l1: 0.113648\n",
      "[2400]\tvalid_0's l1: 0.113324\n",
      "[2700]\tvalid_0's l1: 0.113011\n",
      "[3000]\tvalid_0's l1: 0.112706\n",
      "[3300]\tvalid_0's l1: 0.112483\n",
      "[3600]\tvalid_0's l1: 0.112298\n",
      "[3900]\tvalid_0's l1: 0.11217\n",
      "[4200]\tvalid_0's l1: 0.112044\n",
      "[4500]\tvalid_0's l1: 0.111907\n",
      "[4800]\tvalid_0's l1: 0.111772\n",
      "[5100]\tvalid_0's l1: 0.111703\n",
      "[5400]\tvalid_0's l1: 0.111593\n",
      "[5700]\tvalid_0's l1: 0.111496\n",
      "[6000]\tvalid_0's l1: 0.111416\n",
      "[6300]\tvalid_0's l1: 0.111382\n",
      "[6600]\tvalid_0's l1: 0.11132\n",
      "[6900]\tvalid_0's l1: 0.111269\n",
      "[7200]\tvalid_0's l1: 0.111226\n",
      "[7500]\tvalid_0's l1: 0.111172\n",
      "[7800]\tvalid_0's l1: 0.111127\n",
      "[8100]\tvalid_0's l1: 0.111104\n",
      "[8400]\tvalid_0's l1: 0.111072\n",
      "[8700]\tvalid_0's l1: 0.111019\n",
      "[9000]\tvalid_0's l1: 0.110966\n",
      "[9300]\tvalid_0's l1: 0.110924\n",
      "[9600]\tvalid_0's l1: 0.110914\n",
      "[9900]\tvalid_0's l1: 0.110868\n",
      "--------------------- 第 3 折 ---------------------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:726: UserWarning: 'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. Pass 'early_stopping()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. \"\n",
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:736: UserWarning: 'verbose' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'verbose' argument is deprecated and will be removed in a future release of LightGBM. \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[LightGBM] [Warning] feature_fraction is set=0.8, colsample_bytree=1.0 will be ignored. Current value: feature_fraction=0.8\n",
      "[LightGBM] [Warning] bagging_fraction is set=0.8, subsample=1.0 will be ignored. Current value: bagging_fraction=0.8\n",
      "[LightGBM] [Warning] lambda_l2 is set=2, reg_lambda=0.0 will be ignored. Current value: lambda_l2=2\n",
      "[LightGBM] [Warning] bagging_freq is set=1, subsample_freq=0 will be ignored. Current value: bagging_freq=1\n",
      "[300]\tvalid_0's l1: 0.125049\n",
      "[600]\tvalid_0's l1: 0.119332\n",
      "[900]\tvalid_0's l1: 0.116548\n",
      "[1200]\tvalid_0's l1: 0.114946\n",
      "[1500]\tvalid_0's l1: 0.113844\n",
      "[1800]\tvalid_0's l1: 0.113069\n",
      "[2100]\tvalid_0's l1: 0.112473\n",
      "[2400]\tvalid_0's l1: 0.112064\n",
      "[2700]\tvalid_0's l1: 0.111671\n",
      "[3000]\tvalid_0's l1: 0.111378\n",
      "[3300]\tvalid_0's l1: 0.111146\n",
      "[3600]\tvalid_0's l1: 0.110984\n",
      "[3900]\tvalid_0's l1: 0.110825\n",
      "[4200]\tvalid_0's l1: 0.110625\n",
      "[4500]\tvalid_0's l1: 0.110452\n",
      "[4800]\tvalid_0's l1: 0.110343\n",
      "[5100]\tvalid_0's l1: 0.110244\n",
      "[5400]\tvalid_0's l1: 0.110146\n",
      "[5700]\tvalid_0's l1: 0.11008\n",
      "[6000]\tvalid_0's l1: 0.109986\n",
      "[6300]\tvalid_0's l1: 0.109922\n",
      "[6600]\tvalid_0's l1: 0.109842\n",
      "[6900]\tvalid_0's l1: 0.109785\n",
      "[7200]\tvalid_0's l1: 0.109719\n",
      "[7500]\tvalid_0's l1: 0.109643\n",
      "[7800]\tvalid_0's l1: 0.109602\n",
      "[8100]\tvalid_0's l1: 0.109554\n",
      "[8400]\tvalid_0's l1: 0.109525\n",
      "[8700]\tvalid_0's l1: 0.109465\n",
      "[9000]\tvalid_0's l1: 0.109409\n",
      "[9300]\tvalid_0's l1: 0.109374\n",
      "[9600]\tvalid_0's l1: 0.109337\n",
      "[9900]\tvalid_0's l1: 0.109329\n",
      "--------------------- 第 4 折 ---------------------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:726: UserWarning: 'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. Pass 'early_stopping()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'early_stopping_rounds' argument is deprecated and will be removed in a future release of LightGBM. \"\n",
      "D:\\Anaconda\\Anaconda3\\lib\\site-packages\\lightgbm\\sklearn.py:736: UserWarning: 'verbose' argument is deprecated and will be removed in a future release of LightGBM. Pass 'log_evaluation()' callback via 'callbacks' argument instead.\n",
      "  _log_warning(\"'verbose' argument is deprecated and will be removed in a future release of LightGBM. \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[LightGBM] [Warning] feature_fraction is set=0.8, colsample_bytree=1.0 will be ignored. Current value: feature_fraction=0.8\n",
      "[LightGBM] [Warning] bagging_fraction is set=0.8, subsample=1.0 will be ignored. Current value: bagging_fraction=0.8\n",
      "[LightGBM] [Warning] lambda_l2 is set=2, reg_lambda=0.0 will be ignored. Current value: lambda_l2=2\n",
      "[LightGBM] [Warning] bagging_freq is set=1, subsample_freq=0 will be ignored. Current value: bagging_freq=1\n",
      "[300]\tvalid_0's l1: 0.126383\n",
      "[600]\tvalid_0's l1: 0.120132\n",
      "[900]\tvalid_0's l1: 0.117355\n",
      "[1200]\tvalid_0's l1: 0.115801\n",
      "[1500]\tvalid_0's l1: 0.11479\n",
      "[1800]\tvalid_0's l1: 0.113852\n",
      "[2100]\tvalid_0's l1: 0.113182\n",
      "[2400]\tvalid_0's l1: 0.112685\n",
      "[2700]\tvalid_0's l1: 0.112278\n",
      "[3000]\tvalid_0's l1: 0.111974\n",
      "[3300]\tvalid_0's l1: 0.111733\n",
      "[3600]\tvalid_0's l1: 0.111507\n",
      "[3900]\tvalid_0's l1: 0.111313\n",
      "[4200]\tvalid_0's l1: 0.111167\n",
      "[4500]\tvalid_0's l1: 0.111034\n",
      "[4800]\tvalid_0's l1: 0.110941\n",
      "[5100]\tvalid_0's l1: 0.110828\n",
      "[5400]\tvalid_0's l1: 0.110755\n",
      "[5700]\tvalid_0's l1: 0.110705\n",
      "[6000]\tvalid_0's l1: 0.110643\n",
      "[6300]\tvalid_0's l1: 0.110585\n",
      "[6600]\tvalid_0's l1: 0.110535\n",
      "[6900]\tvalid_0's l1: 0.110469\n",
      "[7200]\tvalid_0's l1: 0.110408\n",
      "[7500]\tvalid_0's l1: 0.110372\n",
      "[7800]\tvalid_0's l1: 0.110334\n",
      "[8100]\tvalid_0's l1: 0.110293\n",
      "[8400]\tvalid_0's l1: 0.110281\n",
      "交叉验证 MAE: 473.09724643933805\n"
     ]
    }
   ],
   "source": [
    "# 使用 LightGBMRegressor 作为模型，对数据进行训练和预测。\n",
    "# 对数据进行五折交叉检验，最后通过将五次模型训练得到的结果平均作为最终预测结果，并将结果保存到文件中供提交。\n",
    "df1 = df.copy()\n",
    "test = df1[df1['price'].isnull()]\n",
    "X_train = df1[df1['price'].notnull()].drop(['price', 'regDate', 'creatDate', 'SaleID', 'regionCode'], axis=1)\n",
    "Y_train = df1[df1['price'].notnull()]['price']\n",
    "X_test = df1[df1['price'].isnull()].drop(['price', 'regDate', 'creatDate', 'SaleID', 'regionCode'], axis=1)\n",
    "# 五折交叉检验\n",
    "cols = list(X_train)\n",
    "oof = np.zeros(X_train.shape[0])\n",
    "sub = test[['SaleID']].copy()\n",
    "sub['price'] = 0\n",
    "feat_df = pd.DataFrame({'feat': cols, 'imp': 0})\n",
    "skf = KFold(n_splits=4, shuffle=True, random_state=2020)\n",
    "\n",
    "clf = LGBMRegressor(\n",
    "    n_estimators=10000,\n",
    "    learning_rate=0.07,  # 0.02,\n",
    "    boosting_type='gbdt',\n",
    "    objective='regression_l1',\n",
    "    max_depth=-1,\n",
    "    num_leaves=31,\n",
    "    min_child_samples=20,\n",
    "    feature_fraction=0.8,\n",
    "    bagging_freq=1,\n",
    "    bagging_fraction=0.8,\n",
    "    lambda_l2=2,\n",
    "    random_state=2020,\n",
    "    metric='mae'\n",
    ")\n",
    "\n",
    "mae = 0\n",
    "for i, (trn_idx, val_idx) in enumerate(skf.split(X_train, Y_train)):\n",
    "    print('--------------------- 第 {} 折 ---------------------'.format(i + 1))\n",
    "    trn_x, trn_y = X_train.iloc[trn_idx].reset_index(drop=True), Y_train[trn_idx]\n",
    "    val_x, val_y = X_train.iloc[val_idx].reset_index(drop=True), Y_train[val_idx]\n",
    "    clf.fit(\n",
    "        trn_x, trn_y,\n",
    "        eval_set=[(val_x, val_y)],\n",
    "        eval_metric='mae',\n",
    "        early_stopping_rounds=300,\n",
    "        verbose=300\n",
    "    )\n",
    "\n",
    "    sub['price'] += np.expm1(clf.predict(X_test)) / skf.n_splits\n",
    "    oof[val_idx] = clf.predict(val_x)\n",
    "    mae += mean_absolute_error(np.expm1(val_y), np.expm1(oof[val_idx])) / skf.n_splits\n",
    "\n",
    "print('交叉验证 MAE:', mae)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成提交文件\n",
    "sub.to_csv('submit.csv', index=False)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
